package address

import (
	"context"
	"net/http"

	"github.com/gin-gonic/gin"

	"mxshop-api/shared/auth"
	"mxshop-api/userop-web/api"
	"mxshop-api/userop-web/forms"
	"mxshop-api/userop-web/global"
	proto "mxshop-api/userop-web/proto/userop/gen/v1"
)

type APIAddress struct {
	ID           int32  `json:"id,omitempty"`
	UserID       int32  `json:"user_id,omitempty"`
	Province     string `json:"province,omitempty"`
	City         string `json:"city,omitempty"`
	District     string `json:"district,omitempty"`
	Address      string `json:"address,omitempty"`
	SignerName   string `json:"signer_name,omitempty"`
	SignerMobile string `json:"signer_mobile,omitempty"`
}

func EntityPbToAPI(a *proto.AddressEntity) APIAddress {
	return APIAddress{
		ID:           a.Id,
		UserID:       a.Address.UserId,
		Province:     a.Address.Province,
		City:         a.Address.City,
		District:     a.Address.District,
		Address:      a.Address.Address,
		SignerName:   a.Address.SignerName,
		SignerMobile: a.Address.SignerMobile,
	}
}

func ValueObjFormToPb(userID int32, form forms.AddressForm) *proto.Address {
	return &proto.Address{
		UserId:       userID,
		Province:     form.Province,
		City:         form.City,
		District:     form.District,
		Address:      form.Address,
		SignerName:   form.SignerName,
		SignerMobile: form.SignerMobile,
	}
}

func List(c *gin.Context) {
	claims, err := auth.ClaimsFromContext(c)
	if err != nil {
		return
	}

	var addressFilter proto.GetAddressListRequest

	// 根据不同的用户类型去定制不同的过滤条件
	switch claims.RoleID {
	case 1: // 普通用户返回自己的地址
		addressFilter.UserId = int32(claims.ID)
	case 2: // 管理员用户返回所有地址
	default:
		c.Status(http.StatusForbidden)
		return
	}

	userOpCli := proto.NewAddressServiceClient(global.UserOpConn)
	addressesResp, err := userOpCli.GetAddressList(context.Background(), &addressFilter)
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	addresses := make([]APIAddress, 0, len(addressesResp.Addresses))
	for _, address := range addressesResp.Addresses {
		addresses = append(addresses, EntityPbToAPI(address))
	}

	c.JSON(http.StatusOK, gin.H{
		"total": addressesResp.Total,
		"data":  addresses,
	})
}

func New(c *gin.Context) {
	userID, err := auth.UserIDFromContext(c)
	if err != nil {
		return
	}

	var addressForm forms.AddressForm
	err = c.ShouldBind(&addressForm)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	userOpCli := proto.NewAddressServiceClient(global.UserOpConn)
	addressResp, err := userOpCli.CreateAddress(context.Background(), ValueObjFormToPb(int32(userID), addressForm))
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	c.JSON(http.StatusCreated, EntityPbToAPI(addressResp))
}

func Update(c *gin.Context) {
	userID, err := auth.UserIDFromContext(c)
	if err != nil {
		return
	}

	var addressID forms.AddressID
	err = c.ShouldBindUri(&addressID)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	var addressForm forms.AddressForm
	err = c.ShouldBind(&addressForm)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	userOpCli := proto.NewAddressServiceClient(global.UserOpConn)
	_, err = userOpCli.UpdateAddress(context.Background(), &proto.AddressEntity{
		Id:      addressID.ID,
		Address: ValueObjFormToPb(int32(userID), addressForm),
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	c.Status(http.StatusCreated)
}

func Delete(c *gin.Context) {
	userID, err := auth.UserIDFromContext(c)
	if err != nil {
		return
	}

	var addressID forms.AddressID
	err = c.ShouldBindUri(&addressID)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	userOpCli := proto.NewAddressServiceClient(global.UserOpConn)
	_, err = userOpCli.DeleteAddress(context.Background(), &proto.DeleteAddressRequest{
		Id:     addressID.ID,
		UserId: int32(userID),
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	c.Status(http.StatusNoContent)
}
